package tan.dft.gps;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

import org.json.JSONObject;

import tan.dft.json.DirectionsJSONParser;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.FragmentManager;
import android.content.Intent;
import android.graphics.Color;
import android.location.Address;
import android.location.Criteria;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnInfoWindowClickListener;
import com.google.android.gms.maps.GoogleMap.OnMapClickListener;
import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener;
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener;
import com.google.android.gms.maps.GoogleMap.OnMarkerDragListener;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.PolylineOptions;

public class ShowMaps extends Activity implements OnMapClickListener,
		OnMarkerClickListener, OnMapLongClickListener, OnMarkerDragListener,
		LocationListener, OnInfoWindowClickListener {

	final int RQS_GooglePlayServices = 1;
	private GoogleMap myMap;
	private TextView tvLocInfo;
	boolean markerClicked;
	private Geocoder geocoder;
	private List<Address> addresses;
	ArrayList<LatLng> mMarkerPoints;
	private String add;
	private LatLng latLng, latLng2;
	private RadioButton rbDriving, rbWalking;
	private RadioGroup rgModes;
	int mMode = 0;
	final int MODE_DRIVING = 0;
	final int MODE_WALKING = 2;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.showmaps);
		tvLocInfo = (TextView) findViewById(R.id.locinfo);
		FragmentManager myFragmentManager = getFragmentManager();
		MapFragment myMapFragment = (MapFragment) myFragmentManager
				.findFragmentById(R.id.map);
		myMap = myMapFragment.getMap();

		myMap.setMyLocationEnabled(true);
		myMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
		LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
		Criteria criteria = new Criteria();
		String provider = locationManager.getBestProvider(criteria, true);
		Location location = locationManager.getLastKnownLocation(provider);
		if (location != null) {
			onLocationChanged(location);
		}
		locationManager.requestLocationUpdates(provider, 20000, 0, this);
		rbDriving = (RadioButton) findViewById(R.id.rb_driving);
		rbWalking = (RadioButton) findViewById(R.id.rb_walking);
		rgModes = (RadioGroup) findViewById(R.id.rg_modes);
		rgModes.setOnCheckedChangeListener(new OnCheckedChangeListener() {
			@Override
			public void onCheckedChanged(RadioGroup group, int checkedId) {
				if (mMarkerPoints.size() >= 2) {
					LatLng origin = mMarkerPoints.get(0);
					LatLng dest = mMarkerPoints.get(1);
					String url = getDirectionsUrl(origin, dest);
					DownloadTask downloadTask = new DownloadTask();
					downloadTask.execute(url);
				}
			}
		});

		mMarkerPoints = new ArrayList<LatLng>();
		geocoder = new Geocoder(this, Locale.getDefault());
		try {
			addresses = geocoder.getFromLocation(location.getLatitude(),
					location.getLongitude(), 1);
			String address = addresses.get(0).getAddressLine(0);
			String city = addresses.get(0).getAddressLine(1);
			String country = addresses.get(0).getAddressLine(2);
			add = address + " | " + city + " | " + country;
			myMap.addMarker(new MarkerOptions()
					.position(
							new LatLng(location.getLatitude(), location
									.getLongitude())).title(add)
					.snippet("Hello"));

		} catch (IOException e) {
			e.printStackTrace();
		}
		latLng2 = new LatLng(location.getLatitude(), location.getLongitude());

		Intent intent = getIntent();
		Bundle bundle = intent.getExtras();
		int idql1 = bundle.getInt("idql1");
		String name = bundle.getString("name");
		Double lat = bundle.getDouble("lat");
		Double lng = bundle.getDouble("lng");
		geocoder = new Geocoder(this, Locale.getDefault());
		try {
			addresses = geocoder.getFromLocation(lat, lng, 1);
			String address = addresses.get(0).getAddressLine(0);
			String city = addresses.get(0).getAddressLine(1);
			String country = addresses.get(0).getAddressLine(2);
			add = "ID QL :" + idql1 + " | " + "Name :" + name + " | " + address
					+ " | " + city + " | " + country;
			myMap.addMarker(new MarkerOptions().position(new LatLng(lat, lng))
					.title(add).snippet("Hello"));
		} catch (IOException e) {
			e.printStackTrace();
		}
		latLng = new LatLng(lat, lng);

		String url = getDirectionsUrl(latLng2, latLng);
		DownloadTask downloadTask = new DownloadTask();
		downloadTask.execute(url);
		myMap.setOnMapClickListener(this);
		myMap.setOnMapLongClickListener(this);
		myMap.setOnMarkerDragListener(this);
		markerClicked = false;
		myMap.setOnInfoWindowClickListener(this);
	}

	private void drawMarker(LatLng point) {
		mMarkerPoints.add(point);
		MarkerOptions options = new MarkerOptions();
		options.position(point);
		geocoder = new Geocoder(this, Locale.getDefault());
		try {
			addresses = geocoder.getFromLocation(point.latitude,
					point.longitude, 1);
			String address = addresses.get(0).getAddressLine(0);
			String city = addresses.get(0).getAddressLine(1);
			String country = addresses.get(0).getAddressLine(2);
			add = address + " | " + city + " | " + country;
		} catch (IOException e) {
			e.printStackTrace();
		}

		if (mMarkerPoints.size() == 1) {
			options.icon(BitmapDescriptorFactory
					.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
		} else if (mMarkerPoints.size() == 2) {
			options.icon(BitmapDescriptorFactory
					.defaultMarker(BitmapDescriptorFactory.HUE_RED));
		}
		options.title(add);
		myMap.addMarker(options);
	}

	private class ParserTask extends
			AsyncTask<String, Integer, List<List<HashMap<String, String>>>> {
		@Override
		protected List<List<HashMap<String, String>>> doInBackground(
				String... jsonData) {
			JSONObject jObject;
			List<List<HashMap<String, String>>> routes = null;
			try {
				jObject = new JSONObject(jsonData[0]);
				DirectionsJSONParser parser = new DirectionsJSONParser();
				routes = parser.parse(jObject);
			} catch (Exception e) {
				e.printStackTrace();
			}
			return routes;
		}

		@Override
		protected void onPostExecute(List<List<HashMap<String, String>>> result) {
			ArrayList<LatLng> points = null;
			PolylineOptions lineOptions = null;
			MarkerOptions markerOptions = new MarkerOptions();
			for (int i = 0; i < result.size(); i++) {
				points = new ArrayList<LatLng>();
				lineOptions = new PolylineOptions();
				List<HashMap<String, String>> path = result.get(i);
				for (int j = 0; j < path.size(); j++) {
					HashMap<String, String> point = path.get(j);
					double lat = Double.parseDouble(point.get("lat"));
					double lng = Double.parseDouble(point.get("lng"));
					LatLng position = new LatLng(lat, lng);
					points.add(position);
				}
				lineOptions.addAll(points);
				lineOptions.width(5);
				if (mMode == MODE_DRIVING)
					lineOptions.color(Color.RED);
				else if (mMode == MODE_WALKING)
					lineOptions.color(Color.BLUE);
			}
			if (result.size() < 1) {
				Toast.makeText(getBaseContext(), "No Points",
						Toast.LENGTH_SHORT).show();
				return;
			}
			// Drawing polyline in the Google Map for the i-th route
			myMap.addPolyline(lineOptions);
		}
	}

	/** A method to download json data from url */
	private String downloadUrl(String strUrl) throws IOException {
		String data = "";
		InputStream iStream = null;
		HttpURLConnection urlConnection = null;
		try {
			URL url = new URL(strUrl);
			// Creating an http connection to communicate with url
			urlConnection = (HttpURLConnection) url.openConnection();
			// Connecting to url
			urlConnection.connect();
			// Reading data from url
			iStream = urlConnection.getInputStream();
			BufferedReader br = new BufferedReader(new InputStreamReader(
					iStream));
			StringBuffer sb = new StringBuffer();
			String line = "";
			while ((line = br.readLine()) != null) {
				sb.append(line);
			}
			data = sb.toString();
			br.close();
		} catch (Exception e) {
			Log.d("Exception while downloading url", e.toString());
		} finally {
			iStream.close();
			urlConnection.disconnect();
		}
		return data;
	}

	// Fetches data from url passed
	private class DownloadTask extends AsyncTask<String, Void, String> {
		// Downloading data in non-ui thread
		@Override
		protected String doInBackground(String... url) {
			// For storing data from web service
			String data = "";
			try {
				// Fetching the data from web service
				data = downloadUrl(url[0]);
			} catch (Exception e) {
				Log.d("Background Task", e.toString());
			}
			return data;
		}

		// Executes in UI thread, after the execution of
		// doInBackground()
		@Override
		protected void onPostExecute(String result) {
			super.onPostExecute(result);
			ParserTask parserTask = new ParserTask();
			// Invokes the thread for parsing the JSON data
			parserTask.execute(result);
		}
	}

	private String getDirectionsUrl(LatLng origin, LatLng dest) {
		// Origin of route
		String str_origin = "origin=" + origin.latitude + ","
				+ origin.longitude;
		// Destination of route
		String str_dest = "destination=" + dest.latitude + "," + dest.longitude;
		// Sensor enabled
		String sensor = "sensor=false";
		// Travelling Mode
		String mode = "mode=driving";
		if (rbDriving.isChecked()) {
			mode = "mode=driving";
			mMode = 0;
		} else if (rbWalking.isChecked()) {
			mode = "mode=walking";
			mMode = 2;
		}
		// Building the parameters to the web service
		String parameters = str_origin + "&" + str_dest + "&" + sensor + "&"
				+ mode;
		// Output format
		String output = "json";
		// Building the url to the web service
		String url = "https://maps.googleapis.com/maps/api/directions/"
				+ output + "?" + parameters;
		return url;
	}

	public void onLocationChanged(Location location) {
		// Getting latitude of the current location
		double latitude = location.getLatitude();
		// Getting longitude of the current location
		double longitude = location.getLongitude();
		// Creating a LatLng object for the current location
		LatLng latLng = new LatLng(latitude, longitude);
		// Showing the current location in Google Map
		myMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
		// Zoom in the Google Map
		myMap.animateCamera(CameraUpdateFactory.zoomTo(15));
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.activity_main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.menu_legalnotices:
			String LicenseInfo = GooglePlayServicesUtil
					.getOpenSourceSoftwareLicenseInfo(getApplicationContext());
			AlertDialog.Builder LicenseDialog = new AlertDialog.Builder(
					ShowMaps.this);
			LicenseDialog.setTitle("Legal Notices");
			LicenseDialog.setMessage(LicenseInfo);
			LicenseDialog.show();
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

	@Override
	protected void onResume() {

		super.onResume();

		int resultCode = GooglePlayServicesUtil
				.isGooglePlayServicesAvailable(getApplicationContext());
		if (resultCode == ConnectionResult.SUCCESS) {
			Toast.makeText(getApplicationContext(),
					"isGooglePlayServicesAvailable SUCCESS", Toast.LENGTH_LONG)
					.show();
		} else {
			GooglePlayServicesUtil.getErrorDialog(resultCode, this,
					RQS_GooglePlayServices);
		}

	}

	@Override
	public void onMapLongClick(LatLng point) {
		tvLocInfo.setText("New marker added@" + point.toString());
		geocoder = new Geocoder(this, Locale.getDefault());
		try {
			addresses = geocoder.getFromLocation(point.latitude,
					point.longitude, 1);
			String address = addresses.get(0).getAddressLine(0);
			String city = addresses.get(0).getAddressLine(1);
			String country = addresses.get(0).getAddressLine(2);
			add = address + "|" + city + "|" + country;
			myMap.addMarker(new MarkerOptions().position(point).title(add)
					.draggable(true));
		} catch (IOException e) {
			e.printStackTrace();
		}

		markerClicked = false;
	}

	@Override
	public void onMarkerDrag(Marker marker) {
		try {
			addresses = geocoder.getFromLocation(marker.getPosition().latitude,
					marker.getPosition().longitude, 1);
			String address = addresses.get(0).getAddressLine(0);
			String city = addresses.get(0).getAddressLine(1);
			String country = addresses.get(0).getAddressLine(2);
			add = address + "|" + city + "|" + country;
			marker.setTitle(add);
		} catch (IOException e) {
			e.printStackTrace();
		}
		marker.setTitle(add);
		tvLocInfo.setText("Marker " + marker.getId() + " Drag@"
				+ marker.getPosition() + "Dia Chi :" + add);

	}

	@Override
	public void onMarkerDragEnd(Marker marker) {
		tvLocInfo.setText("Marker " + marker.getId() + " DragEnd");
		try {
			addresses = geocoder.getFromLocation(marker.getPosition().latitude,
					marker.getPosition().longitude, 1);
			String address = addresses.get(0).getAddressLine(0);
			String city = addresses.get(0).getAddressLine(1);
			String country = addresses.get(0).getAddressLine(2);

			add = address + "|" + city + "|" + country;
			marker.setTitle(add);

		} catch (IOException e) {
			e.printStackTrace();
		}
		marker.setTitle(add);
	}

	@Override
	public void onMarkerDragStart(Marker marker) {
		tvLocInfo.setText("Marker " + marker.getId() + " DragStart");
		try {
			addresses = geocoder.getFromLocation(marker.getPosition().latitude,
					marker.getPosition().longitude, 1);
			String address = addresses.get(0).getAddressLine(0);
			String city = addresses.get(0).getAddressLine(1);
			String country = addresses.get(0).getAddressLine(2);
			add = address + "|" + city + "|" + country;
			marker.setTitle(add);

		} catch (IOException e) {
			e.printStackTrace();
		}
		marker.setTitle(add);
	}

	@Override
	public void onProviderDisabled(String provider) {
	}

	@Override
	public void onProviderEnabled(String provider) {
	}

	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {
	}

	@Override
	public void onMapClick(LatLng point) {
		// TODO Auto-generated method stub
		// Already map contain destination location
		if (mMarkerPoints.size() > -1) {
			FragmentManager fm = getFragmentManager();
			mMarkerPoints.clear();
			myMap.clear();
			LatLng startPoint = latLng2;
			drawMarker(startPoint);
		}

		tvLocInfo.setText(point.toString());
		myMap.animateCamera(CameraUpdateFactory.newLatLng(point));
		drawMarker(point);
		// Checks, whether start and end locations are captured
		if (mMarkerPoints.size() >= 2) {
			LatLng origin = mMarkerPoints.get(0);
			LatLng dest = mMarkerPoints.get(1);
			// Getting URL to the Google Directions API
			String url = getDirectionsUrl(origin, dest);
			DownloadTask downloadTask = new DownloadTask();
			// Start downloading json data from Google Directions API
			downloadTask.execute(url);
		}
	}

	@Override
	public void onInfoWindowClick(Marker marker) {
		Toast.makeText(getApplicationContext(), "DMM", Toast.LENGTH_LONG)
				.show();
		String url = getDirectionsUrl(latLng2, latLng);
		DownloadTask downloadTask = new DownloadTask();
		downloadTask.execute(url);
	}

	@Override
	public boolean onMarkerClick(Marker marker) {

		return false;
	}

}
